"""Command-line interface for SwiftShadow - Typer CLI."""

import asyncio
from pathlib import Path
from uuid import UUID

import typer
from rich.console import Console
from rich.table import Table

from ..core.downloader import DownloadEngine
from ..core.task_manager import TaskManager
from ..models.database import db
from ..models.task import DownloadTask, TaskPriority, TaskStatus
from ..utils.logger import setup_logger

app = typer.Typer(
    name="swiftshadow",
    help="疾影下载器 - 次世代智能下载解决方案",
    add_completion=False,
)
console = Console()


@app.command()
def add(
        url: str = typer.Argument(..., help="Download URL"),
        title: str | None = typer.Option(None, "--title", "-t", help="Custom title"),
        output: str | None = typer.Option(None, "--output", "-o", help="Save path"),
        quality: str | None = typer.Option(None, "--quality", "-q", help="Quality (e.g., 1080p)"),
        priority: str = typer.Option("medium", "--priority", "-p", help="Priority (low/medium/high)"),
        cookies: str | None = typer.Option(None, "--cookies", "-c", help="Path to Netscape-format cookies file"),
) -> None:
    """Adds a new download task.

    Args:
        url: The URL of the resource to download.
        title: Optional custom title for the task.
        output: Optional custom save path for the downloaded file.
        quality: Optional quality specification (e.g., "1080p").
        priority: The priority of the task (low, medium, or high).
        cookies: Path to Netscape-format cookies file.
    """

    async def _add_task() -> None:
        # Initialize logger
        setup_logger(level="INFO")
        # Initialize database
        await db.initialize()

        # Define an asynchronous progress callback function
        async def cli_progress_callback(
                task_id: UUID,
                status: TaskStatus,
                progress: float | None,
                speed: float | None,
                eta: str | None,
                error_message: str | None,
                current_file_size: str | None,
        ) -> None:
            current_task = await task_manager.get_task(task_id)
            if current_task is None:
                return

            if status == TaskStatus.COMPLETED:
                console.print(f"\r[green]✓ Download completed: {current_task.title}[/green]")
            elif status == TaskStatus.FAILED:
                console.print(
                    f"\r[red]✗ Download failed: {error_message or 'Unknown error'}[/red]"
                )
            elif status == TaskStatus.DOWNLOADING and progress is not None:
                progress_bar = "█" * int(progress / 5) + "░" * (20 - int(progress / 5))
                speed_mb = speed / 1024 / 1024 if speed else 0
                file_size_info = f" | Size: {current_file_size}" if current_file_size else ""
                console.print(
                    f"\r[cyan]Progress: [{progress_bar}] {progress:.1f}% | "
                    f"Speed: {speed_mb:.2f} MB/s | ETA: {eta or 'N/A'}{file_size_info}[/cyan]",
                    end="",
                )
            elif status == TaskStatus.PAUSED:
                console.print(f"\r[yellow]Download paused: {current_task.title}[/yellow]", end="")
            elif status == TaskStatus.CANCELLED:
                console.print(f"\r[yellow]Download cancelled: {current_task.title}[/yellow]", end="")

        # Extract video information
        engine = DownloadEngine(progress_callback=cli_progress_callback)
        console.print(f"[yellow]正在获取资源信息: {url}[/yellow]")

        try:
            info = await engine.extract_info(url, cookies=cookies)
            if info is None:
                console.print(f"[red]提取信息失败: 无法获取 {url} 的信息[/red]")
                raise typer.Exit(1)
        except Exception as e:
            console.print(f"[red]提取信息失败: {e}[/red]")
            raise typer.Exit(1)

        # Build task
        task_title = title or info.get("title", "未知标题")
        filename = info.get("_filename", f"{task_title}.mp4")

        if output:
            save_path = Path(output)
        else:
            save_path = Path.cwd() / "downloads" / filename

        # Priority mapping
        priority_map = {
            "low": TaskPriority.LOW,
            "medium": TaskPriority.MEDIUM,
            "high": TaskPriority.HIGH,
        }

        task = DownloadTask(
            url=url,
            title=task_title,
            filename=filename,
            save_path=str(save_path),
            quality=quality,
            priority=priority_map.get(priority.lower(), TaskPriority.MEDIUM).value,
            file_size=info.get("filesize"),
            duration=info.get("duration"),
            uploader=info.get("uploader"),
            thumbnail_url=info.get("thumbnail"),
            cookies=cookies,
        )

        # Add to task manager
        task_manager = TaskManager()
        await task_manager.start()

        task_id = await task_manager.add_task(task)

        console.print(f"[green]✓ Task added: {task_title}[/green]")
        console.print(f"[cyan]Task ID: {task_id}[/cyan]")
        console.print(f"[cyan]Save Path: {save_path}[/cyan]")

        # Wait for task to complete
        console.print("[yellow]Waiting for download to complete...[/yellow]")

        while True:
            current_task = await task_manager.get_task(task_id)
            if current_task is None:
                break

            if current_task.status in (
                    TaskStatus.COMPLETED,
                    TaskStatus.FAILED,
                    TaskStatus.CANCELLED,
            ):
                if current_task.status == TaskStatus.COMPLETED:
                    console.print(f"[green]✓ Download completed: {task_title}[/green]")
                else:
                    console.print(
                        f"[red]✗ Download failed: {current_task.error_message or 'Unknown error'}[/red]"
                    )
                break

            # Display progress
            progress_bar = "█" * int(current_task.progress / 5) + "░" * (
                    20 - int(current_task.progress / 5)
            )
            speed_mb = current_task.speed / 1024 / 1024 if current_task.speed else 0
            console.print(
                f"\r[cyan]Progress: [{progress_bar}] {current_task.progress:.1f}% | "
                f"Speed: {speed_mb:.2f} MB/s[/cyan]",
            )

            await asyncio.sleep(1)

        await task_manager.stop()
        await db.close()

    asyncio.run(_add_task())


@app.command()
def list(
        status: str | None = typer.Option(None, "--status", "-s", help="Filter by status"),
        limit: int = typer.Option(20, "--limit", "-l", help="Maximum number of tasks to display"),
) -> None:
    """Lists all download tasks.

    Args:
        status: Optional status to filter tasks by.
        limit: The maximum number of tasks to display.
    """

    async def _list_tasks() -> None:
        await db.initialize()
        task_manager = TaskManager()

        # Status filter
        status_filter = None
        if status:
            try:
                status_filter = TaskStatus(status)
            except ValueError:
                console.print(f"[red]Invalid status: {status}[/red]")
                raise typer.Exit(1)

        tasks = await task_manager.list_tasks(status=status_filter, limit=limit)

        if not tasks:
            console.print("[yellow]No tasks found[/yellow]")
            return

        # Create table
        table = Table(title=f"Download Task List (Total {len(tasks)} tasks)")

        table.add_column("ID", style="cyan", no_wrap=True)
        table.add_column("Title", style="magenta")
        table.add_column("Status", style="green")
        table.add_column("Progress", justify="right")
        table.add_column("Speed", justify="right")
        table.add_column("Priority", justify="center")

        for task in tasks:
            # Status coloring
            status_color = {
                TaskStatus.PENDING: "yellow",
                TaskStatus.DOWNLOADING: "blue",
                TaskStatus.PAUSED: "cyan",
                TaskStatus.COMPLETED: "green",
                TaskStatus.FAILED: "red",
                TaskStatus.CANCELLED: "dim",
            }.get(task.status, "white")

            # Speed formatting
            speed_str = f"{task.speed / 1024 / 1024:.2f} MB/s" if task.speed else "-"

            # Priority icon
            priority_icon = {
                TaskPriority.LOW.value: "↓",
                TaskPriority.MEDIUM.value: "→",
                TaskPriority.HIGH.value: "↑",
            }.get(task.priority, "→")

            table.add_row(
                str(task.id)[:8],
                task.title[:30],
                f"[{status_color}]{task.status.value}[/{status_color}]",
                f"{task.progress:.1f}%",
                speed_str,
                priority_icon,
            )

        console.print(table)
        await db.close()

    asyncio.run(_list_tasks())


@app.command()
def pause(task_id: str = typer.Argument(..., help="Task ID")) -> None:
    """Pauses a download task.

    Args:
        task_id: The ID of the task to pause.
    """

    async def _pause() -> None:
        await db.initialize()
        task_manager = TaskManager()
        await task_manager.start()

        try:
            success = await task_manager.pause_task(task_id)

            if success:
                console.print(f"[green]✓ Task paused: {task_id}[/green]")
            else:
                console.print("[red]✗ Pause failed[/red]")

        except Exception as e:
            console.print(f"[red]错误: {e}[/red]")
            raise typer.Exit(1)
        finally:
            await task_manager.stop()
            await db.close()

    asyncio.run(_pause())


@app.command()
def resume(task_id: str = typer.Argument(..., help="Task ID")) -> None:
    """Resumes a paused download task.

    Args:
        task_id: The ID of the task to resume.
    """

    async def _resume() -> None:
        await db.initialize()
        task_manager = TaskManager()
        await task_manager.start()

        try:
            success = await task_manager.resume_task(task_id)

            if success:
                console.print(f"[green]✓ Task resumed: {task_id}[/green]")
            else:
                console.print("[red]✗ Resume failed[/red]")

        except Exception as e:
            console.print(f"[red]错误: {e}[/red]")
            raise typer.Exit(1)
        finally:
            await task_manager.stop()
            await db.close()

    asyncio.run(_resume())


@app.command()
def delete(
        task_id: str = typer.Argument(..., help="Task ID"),
        remove_file: bool = typer.Option(False, "--remove-file", "-r", help="Also delete the downloaded file"),
) -> None:
    """Deletes a download task.

    Args:
        task_id: The ID of the task to delete.
        remove_file: If True, also deletes the associated downloaded file.
    """

    async def _delete() -> None:
        await db.initialize()
        task_manager = TaskManager()

        try:
            success = await task_manager.delete_task(task_id, delete_file=remove_file)

            if success:
                console.print(f"[green]✓ Task deleted: {task_id}[/green]")
            else:
                console.print("[red]✗ Deletion failed[/red]")

        except Exception as e:
            console.print(f"[red]错误: {e}[/red]")
            raise typer.Exit(1)
        finally:
            await db.close()

    asyncio.run(_delete())


@app.command()
def formats(url: str = typer.Argument(..., help="Video URL")) -> None:
    """Lists available formats for a given video URL.

    Args:
        url: The URL of the video to inspect.
    """

    async def _get_formats() -> None:
        engine = DownloadEngine()
        console.print(f"[yellow]Fetching available formats: {url}[/yellow]")

        try:
            formats = await engine.get_formats(url)

            if not formats:
                console.print("[yellow]No available formats found[/yellow]")
                return

            # Create formats table
            table = Table(title="Available Formats")

            table.add_column("Format ID", style="cyan")
            table.add_column("Resolution", style="magenta")
            table.add_column("FPS", justify="right")
            table.add_column("File Size", justify="right")
            table.add_column("Video Codec", style="green")
            table.add_column("Audio Codec", style="blue")

            for fmt in formats:
                table.add_row(
                    fmt["format_id"] or "-",
                    fmt["resolution"] or "-",
                    str(fmt["fps"]) if fmt["fps"] else "-",
                    DownloadEngine.format_filesize(fmt["filesize"]),
                    fmt["vcodec"] or "-",
                    fmt["acodec"] or "-",
                )

            console.print(table)

        except Exception as e:
            console.print(f"[red]Failed to get formats: {e}[/red]")
            raise typer.Exit(1)

    asyncio.run(_get_formats())


@app.command()
def gui() -> None:
    """Launch the SwiftShadow GUI."""
    try:
        from ..gui.main_window import launch
        launch()
    except ImportError:
        console.print("[red]✗ GUI module not installed. Please install with 'pip install swiftshadow[gui]'[/red]")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"[red]✗ Failed to launch GUI: {e}[/red]")
        raise typer.Exit(1)


@app.command()
def version() -> None:
    """Show the version of SwiftShadow."""
    console.print("[cyan]SwiftShadow Downloader v0.1.0[/cyan]")
    console.print("[dim]An intelligent download solution based on yt-dlp[/dim]")


if __name__ == "__main__":
    app()
